﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WheelOfCivilization.Map.MapObject.Movable;
using WheelOfCivilization.Map;

namespace WheelOfCivilization.Logic
{
    static class Control
    {
        //CZ: promenna pouzita pri prvnim spusteni pro odhaleni viditelneho okoli 
        //EN: boolean to know, if I'm running method for the first time
        private static bool f = true;
        //CZ: seznam pro ulozeni nove vygenerovanych clusteru 
        //EN: list for saving new generated clusters
        public static List<WorldCluster> newClusters;   
        //<summary>
        //method, witch initializes and controlls application logic
        //</summary>
        internal static void control(object obj)
        {
            //newClusters = new List<WorldCluster>();     //control pri kazdym prubehu smaze newClusters -> ty uz musej bejt ve svetovy mape
            //    if (!f)                                 //if not first run
            //    {
            //        List<MovingObject> movingUnits = Program.playerResources.unitsP.Where(w => w.moving).ToList();
            //        if (movingUnits.Count > 0 && movingUnits != null)
            //        {
            //            System.Threading.Monitor.Enter(movingUnits);
            //            try
            //            {
            //                //CZ: spoustim metodu jen s objekty, ktere se hybou, ty ktere se nehybou stejne nemohou nic objevovat
            //                //EN: I run method only with object, which have moving "flag" (bool moving = true), 
            //                    //those who are not moving don't need to look around, as they cannot discover anything & they'll be alerted 
            //                    //with event-like method when enemy who is moving around reaches them
            //                foreach (MovingObject mo in movingUnits) 
            //                {
            //                    searchNeigborhood(mo);
            //                }
            //            }
            //            finally
            //            {
            //                System.Threading.Monitor.Exit(movingUnits);
            //            }
            //        }
            //    }
            //    else
            //    {
            //        //CZ: poprve prohledam okoli pro vsechny jednotky (ty stojej, ale stejne muzou bejt blizko hranice, takze by videly pres okraj sveta)
            //        //EN: first run - I search around all units
            //        foreach (MovingObject u in Program.playerResources.unitsP)                       
            //        {
            //            searchNeigborhood(u);
            //        }
            //        f = false; //and set f to false
            //    }
            //    if (newClusters != null && newClusters.Count != 0) //if some clusters were created in searchNeigborhood method
            //    {
            //        System.Threading.Monitor.Enter(Program.world.clusterList); //lock the map
            //        try
            //        {
            //            Program.world.clusterList.AddRange(newClusters); //add new clusters to map
            //        }
            //        finally
            //        {
            //            System.Threading.Monitor.Exit(Program.world.clusterList);   //unlock map
            //        }
            //    }
        }

        //<summary>
        //CZ: metoda rozhodujici kde se ma generovat dalsi cluster podle pozice jednotek. Jestlize jednotka vidi pres okraj clusteru && za okrajem neni dalsi cluster -> vygeneruje se novej
        //EN: method, which decides where to generate next cluster according to unit position. 
            //if(unit sees behind edge of cluster unit.inCluster){ 
                //if(no other cluster isn't behind edge){ generate new cluster }
                //else{display old cluster}
        //</summary>
        public static void searchNeigborhood(MovingObject mo) 
        {
            int xmin = mo.pos.X - mo.eyeRange;
            int xmax = mo.pos.X + mo.eyeRange;
            int ymin = mo.pos.Y - mo.eyeRange;
            int ymax = mo.pos.Y + mo.eyeRange;

            WorldCluster neigbourCluster = null;
            newClusters = new List<WorldCluster>();
            bool newCluster = false;
            //CZ: jestlize jsem mimo hranice 
            //EN: if I see behind the edge
            if (xmax > 9) 
            {
                //CZ: jestlize za hranici nic neni 
                //EN: if there is nothing behind
                if (mo.inCluster.neigbourhood[2] == null) 
                {
                    //CZ: vytvorim novej 
                    //EN: create new cluster
                    neigbourCluster = Program.world.generateCluster(mo.inCluster, 2);
                    newClusters.Add(neigbourCluster);
                    newCluster = true; //set the flag to true
                }
                else
                    //CZ: jinak si vezmu ten, co tam je
                    //EN: I take the one present
                    neigbourCluster = mo.inCluster.neigbourhood[2];
                //CZ: odectu od xmax (dosahu videni) velikost clusteru a dostanu "presah" (to je podminka toho forcyklu)
                //EN: substract sizeOfCluster - xmax (position + eyeRange) and I get coordinates visible in neighbor cluster;
                for (int i = 0; i < (xmax - 9); i++)    
                {
                    //CZ: a nastavim vsem polim v dosahu, ze jsou videt
                    //EN: and I set visible = true;
                    neigbourCluster.unmovableContentGS[i, mo.pos.Y].visible = true;
                    //CZ: a nastavim vsem jednotkam v dosahu, ze jsou videt
                    //EN: and I ask, if there are some other movingObjects in eyeRange, if yes, I set them to visible
                    foreach(MovingObject m in neigbourCluster.movableContentGS.Where(w => w.pos.X == i || w.pos.Y == mo.pos.Y)) 
                        m.visible = true;
                }
                //CZ: a nastavim xmax na hranici clusteru -> musim nastavit viditelnost i uvnitr clusteru ve kterym se zrovna pohybuju!
                //EN: and i set xmax to 9, bcs later I need to loop in cluster unit.inCluster to set visibility in the original cluster
                xmax = 9; 
            }
            //CZ: jinak tady to bude trochu oser, pokud nejaka jednotka presahne parametrem eyeRange 9 -> bude videt pres dva clustery a cela tahle metoda bude potrebovat upravy
            //EN: from Lister to Lister: if(eyeRange > 9) { unit sees over two clusters }
            if (xmin < 0)
            {
                if (mo.inCluster.neigbourhood[6] == null)
                {
                    neigbourCluster = Program.world.generateCluster(mo.inCluster, 6);
                    newClusters.Add(neigbourCluster);
                    newCluster = true;
                }
                else
                    neigbourCluster = mo.inCluster.neigbourhood[6];
                for (int i = 10 + xmin; i < 10; i++)
                {
                    neigbourCluster.unmovableContentGS[i, mo.pos.Y].visible = true;
                    foreach (MovingObject m in neigbourCluster.movableContentGS.Where(w => w.pos.X == i || w.pos.Y == mo.pos.Y))
                        m.visible = true;
                }
                xmin = 0;
            }

            if (ymax > 9)
            {
                if (mo.inCluster.neigbourhood[4] == null)
                {
                    neigbourCluster = Program.world.generateCluster(mo.inCluster, 4);
                    newClusters.Add(neigbourCluster);
                    newCluster = true;
                }
                else
                    neigbourCluster = mo.inCluster.neigbourhood[4];
                for (int i = 0; i < (ymax - 8); i++)
                {
                    neigbourCluster.unmovableContentGS[mo.pos.X, i].visible = true;
                    foreach (MovingObject m in neigbourCluster.movableContentGS.Where(w => w.pos.Y == i && w.pos.X == mo.pos.X))
                        m.visible = true;
                }
                ymax = 9;
            }

            if (ymin < 0)
            {
                if (mo.inCluster.neigbourhood[0] == null)
                {
                    neigbourCluster = Program.world.generateCluster(mo.inCluster, 0);
                    newClusters.Add(neigbourCluster);
                    newCluster = true;
                }
                else
                    neigbourCluster = mo.inCluster.neigbourhood[0];
                for (int i = 10 + ymin; i < 10; i++)
                {
                    neigbourCluster.unmovableContentGS[mo.pos.X, i].visible = true;
                    foreach (MovingObject m in neigbourCluster.movableContentGS.Where(w => w.pos.Y == i && w.pos.X == mo.pos.X))
                        m.visible = true;
                }
                ymin = 0;
            }
            //CZ: tady nastavuju viditelnost uvnitr vlastniho clusteru
            //EN: setting visibility inside unit.inCluster
            for (int x = xmin; x < xmax + 1; x++) 
            {
                for (int y = ymin; y < ymax + 1; y++)
                {
                    mo.inCluster.unmovableContentGS[x, y].visible = true;
                    foreach (MovingObject m in mo.inCluster.movableContentGS.Where(w => w.pos.X == x && w.pos.Y == y))
                        m.visible = true;
                }
            }
            //CZ: pokud jsem vytvoril novej
            if (newCluster) 
            {
                System.Threading.Monitor.Enter(Program.world.clusterList);
                try
                {
                    Program.world.clusterList.AddRange(newClusters);
                }
                finally
                {
                    System.Threading.Monitor.Exit(Program.world.clusterList);
                }
            }
        }


    }
}
